package com.wmx.thymeleafapp.utils;

import javax.crypto.Cipher;
import java.security.*;
import java.util.Base64;

/**
 * Java JDK 原生 RSA 加解密
 * 1. 非对称加密，即：PK（PUBLIC_KEY 公钥） 与 SK（ SECRET_KEY 密钥） 不是同一个
 * 2. PK 加密时，必须用 SK 解密、反之  SK 加密时，必须用 PK 解密，
 * 3. PK 决定 SK，但是 PK 很难算出 SK（数学原理：两个大质数相乘，积很难因式分解）
 * 4. 速度慢，适合对少量数据加密
 *
 * @author wangMaoXiong
 * @version 1.0
 * @date 2024/4/13 11:41
 */
public class ReaUtil {

    private static final String ALGORITHM_RSA = "RSA";
    private static final int KEY_PAIR_LENGTH = 2048;

    /**
     * 生成密钥对
     *
     * @return
     * @throws Exception
     */
    public static KeyPair generateKeyPair(String secureRandomSeed) throws Exception {
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(ALGORITHM_RSA);
        //获取实现指定算法（SHA1PRNG）的随机数生成器（RNG）对象.
        SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
        //重新设定此随机对象的种子.
        secureRandom.setSeed(secureRandomSeed.getBytes());
        /**
         * initialize(int keySize)
         * initialize(int keySize, SecureRandom random):使用给定的随机源（random）初始化特定密钥大小的密钥对生成器。
         * keySize: 健的大小值，这是一个特定于算法的度量。值越大，能加密的内容就越多，否则会抛异常：javax.crypto.IllegalBlockSizeException: Data must not be longer than xxx bytes
         * 如 keySize 为 2048 时加密数据的长度不能超过 245 字节。
         */
        keyPairGenerator.initialize(KEY_PAIR_LENGTH, secureRandom);
        return keyPairGenerator.generateKeyPair();
    }

    public static byte[] encrypt(String plainText, PublicKey publicKey) throws Exception {
        Cipher cipher = Cipher.getInstance(ALGORITHM_RSA);
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        return cipher.doFinal(plainText.getBytes());
    }

    public static byte[] decrypt(byte[] encryptedBytes, PrivateKey privateKey) throws Exception {
        Cipher cipher = Cipher.getInstance(ALGORITHM_RSA);
        cipher.init(Cipher.DECRYPT_MODE, privateKey);
        return cipher.doFinal(encryptedBytes);
    }

    public static byte[] sign(String plainText, PrivateKey privateKey) throws Exception {
        Signature signature = Signature.getInstance("SHA256withRSA");
        signature.initSign(privateKey);
        signature.update(plainText.getBytes());
        return signature.sign();
    }

    public static boolean verify(String plainText, byte[] signatureBytes, PublicKey publicKey) throws Exception {
        Signature signature = Signature.getInstance("SHA256withRSA");
        signature.initVerify(publicKey);
        signature.update(plainText.getBytes());
        return signature.verify(signatureBytes);
    }

    public static void main(String[] args) throws Exception {
        String plainText = "AES: Advanced Encrytion Standard（高级加密标准），特点：1. 对称加密  2. 一个 SECRET_KEY（密钥）扩展成多个子 SK，轮加密";
        String secureRandomSeed = "e27568c9-658c-49ea-b178-1437fce69046";

        // 生成密钥对
        KeyPair keyPair = generateKeyPair(secureRandomSeed);

        // 获取公钥和私钥
        PublicKey publicKey = keyPair.getPublic();
        PrivateKey privateKey = keyPair.getPrivate();
        System.out.println("公钥：" + publicKey);
        System.out.println("私钥：" + privateKey);

        // 使用公钥加密
        byte[] encryptedBytes = encrypt(plainText, publicKey);
        String encryptedText = cn.hutool.core.codec.Base64.encode(encryptedBytes);
        System.out.println("密文: " + encryptedText);

        // 使用私钥解密
        byte[] decodeByte = cn.hutool.core.codec.Base64.decode(encryptedText);
        byte[] decryptedBytes = decrypt(decodeByte, privateKey);
        String decryptedText = new String(decryptedBytes);
        System.out.println("解密: " + decryptedText);

        // 使用私钥签名
        byte[] signatureBytes = sign(plainText, privateKey);
        String signatureText = Base64.getEncoder().encodeToString(signatureBytes);
        System.out.println("私钥签名: " + signatureText);

        // 使用公钥验证签名
        boolean isVerified = verify(plainText, signatureBytes, publicKey);
        System.out.println("公钥验证签名: " + isVerified);
    }

}